﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Frw.Protocols.Communications.Tcp.Configuration;

namespace Frw.Protocols.Communications.Tcp
{
    public class Communicator<T> : IDisposable, ICommunicator<T> where T : ICommunicationMessage, new()
    {
        public event EventHandler<EventArgs<T>> DataRecieved;

        public Exception m_lastException = null;
        private string m_ipAddress = string.Empty;
        private int m_port;
        private Thread m_serverThread = null;
        private Thread m_clientThread = null;
        private Thread server = null;
        private TCPServer s = null;
        private string m_sectionGroupName = string.Empty;

        public void Send(T data)
        {
            using (TCPClient s = new TCPClient())
            {
                s.IPAddress = m_ipAddress;
                s.Port = m_port;

                s.SendMessage(data.CommunicationBag.ToString());
            }
        }

        public Communicator()
        {
        }

        public Communicator(string sectionGroupName)
        {
            m_sectionGroupName = sectionGroupName;
        }

        public Exception GetLastException()
        {
            return m_lastException;
        }

        private void SetupServerInternal(string ipAddress, int port)
        {
            s = new TCPServer(port, ipAddress);
            s.dataRecieved += new TCPServer.onDataRecieved(s_dataRecieved);
            Thread server = new Thread(new ThreadStart(s.startServer));
            server.IsBackground = true;
            server.Start();
        }

        private void s_dataRecieved(string data)
        {
            try
            {
                if (DataRecieved != null)
                {
                    ICommunicationMessage bag = new T();
                    bag.CommunicationBag = data;

                    DataRecieved(this, new EventArgs<T>((T)bag));
                }
            }
            catch (Exception ex)
            {
                m_lastException = ex;
            }
        }

        private void SetupClientInternal(string ipAddress, int port)
        {
            m_ipAddress = ipAddress;
            m_port = port;

            using (TCPClient s = new TCPClient())
            {
                s.IPAddress = ipAddress;
                s.Port = port;

                s.SendMessage("HACK");
            }
        }

        public virtual void ActAsServer(string ipAddress, int port)
        {
            SetupServerInternal(ipAddress, port);
        }

        public virtual void ActAsClient(string ipAddress, int port)
        {
            SetupClientInternal(ipAddress, port);
        }

        public virtual void ActAsServer()
        {
            CommunicatorSection section = CommunicatorSection.GetSection(m_sectionGroupName, "CommunicatorSection");
            if (section != null)
            {
                CommunicatorElement element = section.GetElement2("server");

                if (element != null)
                {
                    //SetupServerInternal(element.IpAddress, element.Port);

                    m_serverThread = new Thread(() => SetupServerInternal(element.IpAddress, element.Port));
                    m_serverThread.IsBackground = true;
                    m_serverThread.Start();
                }
            }
        }

        public virtual void ActAsClient()
        {
            CommunicatorSection section = CommunicatorSection.GetSection(m_sectionGroupName, "CommunicatorSection");
            if (section != null)
            {
                CommunicatorElement element = section.GetElement2("client");

                if (element != null)
                {
                    //SetupClientInternal(element.IpAddress, element.Port);

                    m_clientThread = new Thread(() => SetupClientInternal(element.IpAddress, element.Port));
                    m_clientThread.IsBackground = true;
                    m_clientThread.Start();
                }
            }
        }

        public void Dispose()
        {
            if (s != null)
            {
                s.Dispose();
                s = null;
            }

            if (server != null)
            {
                server.Abort();
                server = null;
            }

            if (m_clientThread != null)
            {
                m_clientThread.Abort();
                m_clientThread = null;
            }

            if (m_serverThread != null)
            {
                m_serverThread.Abort();
                m_serverThread = null;
            }
        }
    }
}
